#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/devinfo.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/list.h>
#include <linux/printk.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/timer.h>
#include <asm/current.h>
#include <linux/printk.h>
#include <asm/pgtable.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/types.h>

static dev_t eint_devid;                  
static struct cdev eint_cdev;           
static struct class *eint_class;         
static struct device *eint_device;
static atomic_t atomic_flag = ATOMIC_INIT(1);

static int open(struct inode *inode, struct file *file)
{
    if (!atomic_dec_and_test(&atomic_flag)) {
        // 减去了1,加1
        atomic_inc(&atomic_flag);
        return -EBUSY;
    }
    
    return 0;
}

static int close(struct inode *inode, struct file *file)
{
    atomic_inc(&atomic_flag);

    return 0;
}

static int eint_key_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
    int ret = 0;
    int val = 1;
    
    // 成功返回0, 失败，返回有多少个Bytes未完成copy
    ret = copy_to_user(buf, &val, size);
    if (ret) {
        pr_err("copy_to_user mem_addr failed\n");
        return size - ret;
    }
    
    return size;
}


static struct file_operations eint_key_fops = {
    .owner  =   THIS_MODULE,
    .read   =   eint_key_read,
    .open   =   open,
    .release =  close,
};

/**
 * 当驱动和硬件信息匹配成功之后，就会调用probe函数，驱动所有的资源的注册和初始化全部放在probe函数中
 */
static int eint_key_probe(struct platform_device *pdev)
{
    struct device_node *np = NULL;
    int ret = 0;
    
    np = pdev->dev.of_node;
    // 通过platform_device获取设备节点
    if (np == NULL) {
        dev_err(&pdev->dev, "eint_key_probe failed");
        return -EINVAL;
    }

    /* 4. 动态分配字符设备号 */
    alloc_chrdev_region(&eint_devid, 0, 1, "eint_key");

    /* 5.初始化字符设备，添加字符设备 */
    cdev_init(&eint_cdev, &eint_key_fops);
    cdev_add(&eint_cdev, eint_devid, 1);


    /* 6.创建类,它会在sys目录下创建/sys/class/dtsled这个类  */
    eint_class = class_create(THIS_MODULE, "eint_key_c");
    if (IS_ERR(eint_class)) {
        dev_err(&pdev->dev, "create class failed\n");
        ret = PTR_ERR(eint_class);
        return -ret;
    }

    /* 7. 在/sys/class/led下创建dtsled设备，然后mdev通过这个自动创建/dev/dtsled这个设备节点 */
    eint_device = device_create(eint_class, NULL, eint_devid, NULL, "eint_key");
    if (IS_ERR(eint_device)) {
         dev_err(&pdev->dev, "create device failed\n");
         ret = PTR_ERR(eint_device);
        return -ret;
    }

    return 0;
}

/**
 * 硬件信息被移除了，或者驱动被卸载了，全部要释放，释放资源的操作就放在该函数中
 */
static int eint_key_remove(struct platform_device *pdev)
{

    /* 注销类、以及类设备 */
    device_destroy(eint_class, eint_devid);
    class_destroy(eint_class);

    /* 删除设备，卸载注册的设备编号 */
    cdev_del(&eint_cdev);
    unregister_chrdev_region(eint_devid, 1);

    return 0;
}

/**
 * 用于设备树匹配
 */
static const struct of_device_id eint_key_dt_match[] = {
    { .compatible = "eint-keys", },
    {},
};

/**
 * platform驱动
 */
static struct platform_driver eint_key_driver = {
    .probe = eint_key_probe,
    .remove = eint_key_remove,
    .driver = {
        .name = "eint_key",
        .of_match_table = eint_key_dt_match,  // 匹配列表
    }
};


static int eint_key_init(void)
{
    int ret = platform_driver_register(&eint_key_driver);
    if (ret < 0) {
        pr_err("eint_key_init platform_driver_register failed");
        return -EINVAL;
    }

    return 0;
}

/**
 * platform驱动模块出口
 */
static void eint_key_exit(void)
{
    platform_driver_unregister(&eint_key_driver);
}

module_init(eint_key_init);
module_exit(eint_key_exit);

MODULE_AUTHOR("huang");
MODULE_DESCRIPTION("jz2440 eint key driver");
MODULE_LICENSE("GPL");





